home *** CD-ROM | disk | FTP | other *** search
/ SPACE 2 / SPACE - Library 2 - Volume 1.iso / telecom / 46 / gem / gmcl16.doc < prev    next >
Encoding:
Text File  |  1986-08-15  |  15.8 KB  |  292 lines

  1.    Permission to reprint or excerpt is granted only if the
  2. following line appears at the top of the article:
  3.    ANTIC PUBLISHING INC.,COPYRIGHT 1986.  REPRINTED BY PERMISSION.
  4.  
  5.    PROFESSIONAL GEM By Tim Oren
  6.    Column #16 -  Interface Potpourri #1
  7.  
  8.      This issue of ST PRO GEM,  number 16 in the series,  presents
  9. code  implementing  several user  interface  techniques:  progress
  10. indicators, rubber boxes, and draggable boxes with mouse sensitive
  11. targets.   The  code  also  includes  some  utility  routines  for
  12. handling resources, event calls, and VDI line drawing.
  13.  
  14.      The  downloads  for this column are available on DL3  of  the
  15. ATARI16 SIG: PCS-58.  Note the plural - in addition to the usual C
  16. sources  stored  in GMCL16.C,  the files  GMCL16.RSC,  GMCL16.DFN,
  17. GMCL16.H,  and  GMCL16.RSH  are a template resource  for  building
  18. progress boxes.   GMCL16.RSC is the resource binary,  and GMCL16.H
  19. is  its  symbol binding file,  to be used with GMCL16.C.   The RSH
  20. file  is  a C image of the resource - you would need  STCREATE  to
  21. regenerate it.
  22.  
  23.      GMCL16.DFN is the binary symbol file for the resource.  It is
  24. in  the format used by the NEW ST Resource Construction  Set.   If
  25. you are a developer, you should download this new version from DL7
  26. of PCS-57.   It fixes a number of bugs, and has a much faster user
  27. interface.
  28.  
  29.      MAKING PROGRESS.   The need for feedback in interface designs
  30. has  been  discussed in previous columns.   One instance which  is
  31. often  necessary is the so-called progress indicator.   A progress
  32. indicator is used when your application is doing a long operation.
  33. It  shows that the function is continuing satisfactorily,  and  is
  34. not hung in a loop.  When possible, it also gives an indication of
  35. the  fraction  of  the operation which has  been  completed.   The
  36. thermometer  bars  on the Desktop format and copy  operations  are
  37. examples.
  38.  
  39.      The sample code shows two types of progress indicator.   Both
  40. are  built within the structure of a dialog resource.   The  first
  41. type  uses  a variable line of text to describe each phase  of  an
  42. operation as it occurs.  The rewriting of the text provides action
  43. on  the  screen;  the  fact that it is different each  time  gives
  44. reassurance  that  the program is not hung.   The second  type  of
  45. indicator  is the thermometer bar.   This is more useful when  the
  46. operation  is  uniform,  allowing  you to  estimate  the  fraction
  47. completed.  Let's look at the code.
  48.  
  49.      The routines beg_prog() and end_prog() are common to the  two
  50. types.   The  code is very similar to the standard dialog handling
  51. procedure,  but is broken into two parts.  Beg_prog() assumes that
  52. the  progress  indicator  box is defined by a  dialog  tree  named
  53. PROGRESS.   Such  a  tree is provided in  GMCL16.RSC.   Beg_prog()
  54. makes  the usual calls to center and draw the box.   The rectangle
  55. computed in the centering operation is stored via a GRECT  pointer
  56. passed  in  the  parameter.   This rectangle compensates  for  the
  57. outline  around the box,  and must be supplied to end_prog()  when
  58. the operation is complete.
  59.  
  60.      The  first version of set_prog() in the  download  implements
  61. the changing text progress indicator.  It looks in a tree labelled
  62. STRINGS for the object number which is passed as a parameter.   It
  63. is assumed that this object is a G_STRING.  The address of the new
  64. text  is loaded from the object's ob_spec field.   (For those with
  65. the  new RCS,  it would be easy to alter this routine to use  free
  66. strings.  Simply replace the first two lines with:
  67.      rsrc_gaddr(R_STRING, strno, &saddr);
  68. and  supply parameters which are the names of strings in  a  FRSTR
  69. box.)
  70.  
  71.      Once the new text is found,  the set_text() utility is called
  72. to  update  the TEDINFO attached to object PLINE in  the  PROGRESS
  73. tree.   Set_text()  will insert the new text address in  te_ptext,
  74. and the new text length in te_txtlen.   Disp_obj() is then used to
  75. redraw only the rectangle belonging to PLINE.
  76.  
  77.      PLINE  must  be defined as a G_BOXTEXT object  with  a  solid
  78. white  background,  and with the CENTERED attribute set.   It must
  79. extend entirely across the progress box.  This guarantees that the
  80. previous  text  will  be covered over,  and the new text  will  be
  81. centered in the box.
  82.  
  83.      The  second version of set_prog() implements the  thermometer
  84. bar progress indicator.  The PROGRESS tree also includes an object
  85. PROBOX  which  defines the outline of the thermometer.   It  is  a
  86. G_BOX  object  with a solid white background,  and  a  one-outside
  87. border.   The  object  PROBAR is nested inside it,  with the  left
  88. edges  matching.   PROBAR  is  also  a G_BOX,  with  a  solid  red
  89. background  and a one-outside border as well.   Set_prog() creates
  90. the thermometer effect by growing and redrawing PROBAR.
  91.  
  92.      Set_prog()  requires two parameters.   Maxc is an estimate of
  93. the total duration of the operation, in arbitrary units.  Value is
  94. the (new) amount completed,  in the same units.  Set_prog performs
  95. two operations.   First,  it computes the fraction value/maxc, and
  96. sets PROBAR to that fraction of the width of PROBOX.   Second,  it
  97. computes the rectangle which is the difference between the old and
  98. new  widths of PROBAR,  and redraws only that part of the progress
  99. box.   This  prevents  an  annoying flash on the screen  when  the
  100. indicator is updated.
  101.  
  102.      These two types of progress indicators have been presented in
  103. separate routines for convenience in explanation.   You can easily
  104. combine  them  in a single procedure to create an  indicator  with
  105. both effects.
  106.  
  107.      The  final progress indicator routine is  called  esc_prog().
  108. During  many lengthy operations is desirable to provide  an  abort
  109. option  to the user.   Esc_prog() lets you do this by polling  the
  110. keyboard  for  an escape (ESC) character.   A zero timer value  is
  111. used  to guarantee an immediate return if no character  is  found.
  112. Characters other than escape are ignored.
  113.  
  114.      Esc_prog()  returns TRUE if an abort is requested,  and FALSE
  115. if  the  operation is to continue.   In your application,  you can
  116. either  pair  calls  to  set_prog()  and  esc_prog(),   or  recode
  117. set_prog()  to automatically make the abort check.   In any  case,
  118. you  should add an information line to the progress  box,  telling
  119. the user how the operation may be halted.
  120.  
  121.      Of  course,  this type of progress indicator is not the  only
  122. option  available on the ST.   Other ideas such as changing window
  123. titles,  or displaying a succession of differing icons are equally
  124. valid.   Sometimes  the nature of your application may suggest  an
  125. alternate metaphor.  For instance, the progress of recalculating a
  126. spreadsheet might be indicated by darkening successive columns  in
  127. a  miniature  image  of the sheet.   Occasionally,  the  computing
  128. operation  is  visual  itself,  and will not require  an  explicit
  129. indicator.   An  example  is  redisplaying  objects  in  a  2D  or
  130. 3D drawing program.
  131.  
  132.      BOXED  IN.   The  second part of the download implements  two
  133. types  of user interaction using the mouse.   The first creates  a
  134. "rubber  box"  on  the  screen,  that  is,  a box  whose  size  is
  135. controlled  by  moving  the mouse.   This is similar  to  the  AES
  136. graf_rubberbox  call,  but allows the box to move in any direction
  137. from  its origin,  while the GEM function only allows movement  to
  138. the lower right.
  139.  
  140.      The second technique allows the user to drag the outline of a
  141. box around the screen using the mouse.   Again, this is similar to
  142. the AES graf_dragbox call, but this version is augmented with code
  143. which "hotspots" selectable objects when the mouse and object pass
  144. over  them.   These routines are another illustration of the usage
  145. of  the evnt_multi function,  and its combination with VDI drawing
  146. to create new interaction techniques.
  147.  
  148.      The  "rubber  box" subroutine is called  fourway_box().   Its
  149. parameters are the current VDI handle (NOT a window handle!),  and
  150. two  GRECT  pointers.   The first GRECT must have its g_x and  g_y
  151. initialized  with the fixed point of the rubber box.   The  second
  152. GRECT contains an outer bound box for the stretching action.
  153.  
  154.      Fourway_box()  begins  by setting the VDI  drawing  mode  and
  155. color.   The  exclusive  or,  black  combination  guarantees  that
  156. redrawing  a figure twice in the same location will exactly  erase
  157. it.  Next, the routine asserts the mouse control flag.  This stops
  158. the  window manager from tracking the mouse,  with the effect that
  159. menus will not drop down during the operation.
  160.  
  161.      The  fixed coordinates are saved in the variables ox and  oy,
  162. and  an initial mouse reading is obtained with  graf_mkstate.   At
  163. this point, the event loop is entered.
  164.  
  165.      At each iteration,  the loop finds the upper left most of the
  166. fixed  vertex  and  the current mouse position,  and  updates  the
  167. tracking GRECT accordingly.   A call to the utility rc_intersect()
  168. is  used  to  restrict the size of the rubber  box  to  the  given
  169. limiting  rectangle.   Note that if you need a lower limit to  the
  170. size of the rubber box, it can be achieved by adding another GRECT
  171. pointer "lower" to the parameter list, and using the call
  172.      rc_union(lower, rubber);
  173. This  works because the union operation selects the larger of  two
  174. rectangles if they are nested.
  175.  
  176.      Rub_wait()  will be described in detail below.   Its  returns
  177. are the new mouse position, and an indication of the current mouse
  178. button  state.   If  the button remains down,  the loop continues.
  179. When the button is released,  the rubber box terminates,  since it
  180. is   a   "spring-loaded"   modal   operation.     Before   ending,
  181. fourway_box()  returns mouse control to the window  manager.   The
  182. return  from the routine is found in the rubber GRECT,  and is the
  183. final extent of the box.
  184.  
  185.      Rub_wait()  is  a utility used by both box  techniques.   Its
  186. purpose  is  to do one step of the box animation,  and wait for  a
  187. mouse  movement,   or  the  release  of  the  button.   Rub_wait()
  188. preserves the state of the screen.
  189.  
  190.      The  first action is to draw an exclusive or'ed  dotted  line
  191. box at the given rectangle.   Next, rub_wait() calls evnt_multi to
  192. wait for the mouse button to come up,  or the mouse to move out of
  193. a one pixel rectangle.   When the event is detected, the same code
  194. is  used  to remove the box.   A value of TRUE is returned if  the
  195. mouse  button is still down;  the curious logical construction  is
  196. necessary since BOTH events could occur at once.
  197.  
  198.      A  short examination of the vdi_xbox() code is  also  useful.
  199. After converting the rectangle to polyline format, the vdi_xline()
  200. routine  is called.   Vdi_xline draws a dotted line,  but does not
  201. use the VDI line style attribute.  This is avoided because the VDI
  202. has  problems with corner points when drawing styled lines in  XOR
  203. mode.   Instead,  a  selection  is made from a set of user defined
  204. line  styles,  based  on  the  direction of the  stroke,  and  the
  205. odd/evenness of the starting horizontal pixel.   This assures that
  206. the figure will be exactly erasable.
  207.  
  208.      HOT STUFF?  The drag box routine is more subtle, because care
  209. is  needed  to  correctly synchronize the movement  of  the  mouse
  210. cursor and the box,  and the highlighting of target objects.   The
  211. parameters  vdi_handle  and  limit  are  identical  to  those   in
  212. fourway_box().  The GRECT pointed to by box contains the width and
  213. height of the movable box when hot_dragbox() is entered.   On exit
  214. it  also  contains  the  last x,y coordinates  of  the  box.   The
  215. variable tree is a pointer to the root of a resource tree defining
  216. the  hot  spots  for  the drag  operation.   Only  objects  tagged
  217. SELECTABLE  are hotspotted.   Hot_dragbox() returns the number  of
  218. such  an object if the box is "dropped" on it,  otherwise a NIL is
  219. returned.
  220.  
  221.      Initialization  proceeds  as above,  until  the  graf_mkstate
  222. call.   Here  is the first potential synchronization problem.   If
  223. the  user moves the mouse very quickly after initiating the  drag,
  224. it may already be outside the box by the time graf_mkstate samples
  225. the position.   The min/max operations given lock the box onto the
  226. cursor, no matter where it has strayed.  The mouse/box offsets, ox
  227. and oy, will remain constant for the rest of the operation.
  228.  
  229.      Hover_obj  will  contain the number of the  object  which  is
  230. currently  highlighted.   It is initialized to NIL,  indicating no
  231. object is currently marked.   Hot_dragbox() now enters a loop with
  232. termination conditions identical to the rubber box.
  233.  
  234.      The  current  desired  position of the  box  is  computed  by
  235. subtracting the box/mouse offset from the current mouse  position.
  236. The  rc_constrain() call ensures that the box will not  leave  the
  237. bounding rectangle.   Note that rc_intersect would not work here -
  238. it  would  alter  the  size of  the  draggable  box,  rather  than
  239. "nudging" it back into the bounds.
  240.  
  241.      Upon  return from rub_wait(),  a number of conditions must be
  242. checked  to  determine the correct object to  highlight,  if  any.
  243. First,  we  must  make sure that the mouse is actually within  the
  244. legal bounds.   If not,  there may be an ambiguous selection, with
  245. the mouse over one object and the box over another.   We choose to
  246. do nothing in this case,  and set hover_obj to NIL.   If the mouse
  247. is in bounds, objc_find looks for a target object.  If one exists,
  248. it must be SELECTABLE, or it is forced to NIL.
  249.  
  250.      Next  the new object,  stored in ret_obj,  is compared to the
  251. old highlighted object,  in hover_obj.   If they are different,  a
  252. switch  must  be  made.   Since either could be NIL,  a  check  is
  253. necessary before calling obj_toggle to invert/reinvert the  screen
  254. image  of  the  object.   When  the loop is  complete,  the  final
  255. hover_obj  is  returned  to  normal state  before  its  number  is
  256. returned.
  257.  
  258.      You  may notice that this method of highlighting  objects  is
  259. different from the incremental tree descent and rectangles  method
  260. presented  in  column 13.   While not as efficient,  the objc_find
  261. technique  is simpler to code and may be adequate for  many  uses.
  262. If  your program will make heavy use of the drag box  routine,  or
  263. will  have  large  trees  of  target  objects,  you  may  wish  to
  264. integrate    the    incremental   hotspotting    algorithm    with
  265. hot_dragbox().   This would be simple to do; just use evnt_multi's
  266. second  mouse  rectangle for the states associated with  the  hot-
  267. spotter.   The  single  pixel rectangles would have to remain,  in
  268. order to maintain the animation effects.
  269.  
  270.      A  FEW  CHANGES.   The  observant may have noticed  that  the
  271. promised  code for popup menus did not make it into  this  column.
  272. Instead,  it  will  appear in column 18 along with more  "graphics
  273. potpourri"  and  feedback replies.   The intervening  installment,
  274. number  17,  will  present  and  document the source  code  for  a
  275. complete   IBM/Atari GEM Resource conversion program.   This  will
  276. appear  concurrently with Mark Skapinker's article on  IBM/ST  GEM
  277. conversions  in  the second issue of START.   While  this  program
  278. will be of direct use to only a minority of ST developers, it will
  279. contain  utility code useful to all,  as well as demonstrations of
  280. dialog handling and the internal structure of resources.
  281.  
  282.      Finally,  you  may also notice that the so-called portability
  283. macros have disappeared from the download.   Indeed, they are gone
  284. for good.   Since the beginning of this column,  the growth of the
  285. ST GEM developer community has outstripped that on the PC.   It no
  286. longer  seems  appropriate  to  inconvenience  ST  developers  and
  287. violate  standard C syntax for the sake of Intel's  design  flaws.
  288. Those  who still need compatibility with the PC may achieve it  by
  289. compiling under Intel large model,  or by writing "sed" scripts to
  290. translate   (tree+obj)->ob_spec  and  the  like  to  their   macro
  291. equivalents.
  292.